﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;

namespace NewEditorNS
{
    public class LoadManager_WWW : MonoBehaviour
    {
        public static LoadManager_WWW instance;

        public static string filePathHead = "file:///";

        /// <summary>www缓存</summary>
        public Dictionary<string, WWW> loadcache = new Dictionary<string, WWW>();
        /// <summary>加载计数</summary>
        public Dictionary<WWW, List<LoadVO_WWW>> cacheRecord = new Dictionary<WWW, List<LoadVO_WWW>>();

        public List<LoadVO_WWW> theLoadList = new List<LoadVO_WWW>();
        public LoadVO_WWW curLoadVO_WWW;
        public bool isLoading = false;
        public int TaskNum = 0;

        public bool DebugModel = false;

        void Awake()
        {
            instance = this;
        }

        void Update()
        {
            if (DebugModel)
                TaskNum = theLoadList.Count;
        }

        void cancelLoad(LoadVO_WWW tarLoadVO_WWW)
        {
            if (tarLoadVO_WWW.isLoading)
            {
                theLoadList.Remove(tarLoadVO_WWW);
                if (curLoadVO_WWW == tarLoadVO_WWW)
                {
                    StopCoroutine(curLoadCoroutine);
                    loadNext();
                }
            }
        }

        public void Unload(LoadVO_WWW LoadVO_WWW)
        {
            if (LoadVO_WWW == null || LoadVO_WWW.path == null)
                return;

            if (!loadcache.ContainsKey(LoadVO_WWW.path))
            {
                cancelLoad(LoadVO_WWW);
            }
            else
            {
                WWW www = loadcache[LoadVO_WWW.path];
                if (cacheRecord.ContainsKey(www))
                {
                    List<LoadVO_WWW> recoradList = cacheRecord[www];
                    recoradList.Remove(LoadVO_WWW);
                    LoadVO_WWW.isLoading = false;
                    LoadVO_WWW.www = null;
                    if (recoradList.Count <= 0)
                    {
                        loadcache.Remove(LoadVO_WWW.path);
                        cacheRecord.Remove(www);
                        if (www.assetBundle != null)
                            www.assetBundle.Unload(true);
                        www.Dispose();
                    }
                }
            }
        }

        public void InsertLoad(LoadVO_WWW LoadVO_WWW)
        {
            bool isIn = false;
            if (theLoadList.Contains(LoadVO_WWW))
                theLoadList.Remove(LoadVO_WWW);
            for (int i = 0, length = theLoadList.Count; i < length; i++)
            {
                if (theLoadList[i].priority >= LoadVO_WWW.priority)
                {
                    theLoadList.Insert(i, LoadVO_WWW);
                    isIn = true;
                    break;
                }
            }
            if (!isIn)
                theLoadList.Add(LoadVO_WWW);
        }

        /// <summary>加载</summary>
        /// <param name="priority">优先级, 越小越高 area=1 building = 2 wall = 3 comp = 3</param>
        /// <param name="loadLocalFile">加载本地文件?</param>
        public LoadVO_WWW Load(string path, Action<WWW> callback, Action<WWW, string> onFailCallback = null,
            bool needCache = false, int priority = 5, bool loadLocalFile = true)
        {
            if (loadLocalFile && !path.Contains(filePathHead))
                path = filePathHead + path;

            LoadVO_WWW LoadVO_WWW = new LoadVO_WWW(path, callback, onFailCallback, needCache, priority);
            if (loadLocalFile && !File.Exists(path.Remove(0, filePathHead.Length)))
            {
                LoadVO_WWW.isLoading = false;
                onFailCallback(null, "未找到该文件: "+path);
                return LoadVO_WWW;
            }
            if (loadcache.ContainsKey(path) && loadcache[path] != null)
            {
                //读取缓存 并记录引用
                LoadVO_WWW.www = loadcache[path];
                cacheRecord[loadcache[path]].Add(LoadVO_WWW);
                if (callback != null)
                    callback(loadcache[path]);
            }
            else
            {
                InsertLoad(LoadVO_WWW);
                if (!isLoading)
                    loadNext();
            }

            LoadVO_WWW.isLoading = true;
            return LoadVO_WWW;
        }

        public void LoadAll(List<string> urlArr, Action<Dictionary<string, WWW>> onAllLoaded = null)
        {
            Dictionary<string, WWW> resDic = new Dictionary<string, WWW>();
            int length = urlArr.Count;
            int lastCount = length;
            for (int i = 0; i < length; i++)
            {
                string url = urlArr[i];
                Load(url, www =>
                {
                    resDic.Add(url, www);
                    lastCount--;
                    if (lastCount == 0)
                        onAllLoaded(resDic);
                });
            }
        }

        public void LoadAll(string[] urlArr, Action<Dictionary<string, WWW>> onAllLoaded = null)
        {
            Dictionary<string, WWW> resDic = new Dictionary<string, WWW>();
            int length = urlArr.Length;
            int lastCount = length;
            for (int i = 0; i < length; i++)
            {
                string url = urlArr[i];
                Load(url, www =>
                {
                    resDic.Add(url, www);
                    lastCount--;
                    if (lastCount == 0)
                        onAllLoaded(resDic);
                });
            }
        }

        void loadNext()
        {
            if (theLoadList.Count >= 1)
            {
                isLoading = true;
                curLoadVO_WWW = theLoadList[0];
                curLoadCoroutine = enumLoad(curLoadVO_WWW);
                StartCoroutine(curLoadCoroutine);
            }
            else
            {
                isLoading = false;
            }
        }

        IEnumerator curLoadCoroutine;

        IEnumerator enumLoad(LoadVO_WWW LoadVO_WWW)
        {
            WWW www = new WWW(LoadVO_WWW.path);
            yield return www;
            List<LoadVO_WWW> loadToRemove = new List<LoadVO_WWW>();

            for (int i = 0, len = theLoadList.Count; i < len; i++)
            {
                LoadVO_WWW tarLoadVO_WWW = theLoadList[i];
                if (tarLoadVO_WWW.path == LoadVO_WWW.path)
                {
                    loadToRemove.Add(tarLoadVO_WWW);
                    tarLoadVO_WWW.www = www;
                }
            }
            //Debug.Log(LoadVO_WWW.path + "加载完成, 执行回调" + loadToRemove.Count+"个");

            if (www.error == null)
                loadcache.AddRep(LoadVO_WWW.path, www);

            foreach (var finishedLoad in loadToRemove)
            {
                theLoadList.Remove(finishedLoad);

                if (www.error == null)
                {
                    List<LoadVO_WWW> recoradList;

                    if (cacheRecord.ContainsKey(LoadVO_WWW.www))
                        recoradList = cacheRecord[LoadVO_WWW.www];
                    else
                    {
                        recoradList = new List<LoadVO_WWW>();
                        cacheRecord.Add(LoadVO_WWW.www, recoradList);
                    }
                    recoradList.Add(finishedLoad);
                    LoadVO_WWW.isLoading = false;
                    if (finishedLoad == null || finishedLoad.callback == null)
                    {
                        Debug.Log(finishedLoad == null);
                    }
                    finishedLoad.callback(www);
                }
                else if (LoadVO_WWW.onFailCallback != null)
                {
                    LoadVO_WWW.isLoading = false;
                    finishedLoad.onFailCallback(www, www.error);
                }
                else
                {
                    LoadVO_WWW.isLoading = false;
                    Debug.Log("default fail callback: \r\n" + www.url + "\r\n" + www.error);
                }
            }
            loadNext();
        }
    }
    public class LoadVO_WWW
    {
        public WWW www;
        /// <summary>进入加载队列后置true</summary>
        public bool isLoading = false;

        public string path;
        public Action<WWW> callback;
        public Action<WWW, string> onFailCallback;
        public bool needCache;
        public int priority;

        public LoadVO_WWW(string path, Action<WWW> callback, Action<WWW, string> onFailCallback, bool needCache, int priority)
        {
            this.path = path;
            this.callback = callback;
            this.onFailCallback = onFailCallback;
            this.needCache = needCache;
            this.priority = priority;
        }
    }
}
